package com.xuelang.pipeline.artifact.app.harborv2.config;

import com.alibaba.fastjson2.JSON;
import com.xuelang.pipeline.artifact.app.harborv2.xo.ApiErrorXO;
import com.xuelang.pipeline.artifact.app.nexus3v1.exception.ArtifactException;
import com.xuelang.pipeline.artifact.app.nexus3v1.xo.ApiResponseXO;
import feign.*;
import feign.codec.Decoder;
import feign.codec.ErrorDecoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHeaders;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Optional;

/**
 * @author xiwen.zxg
 * @since 2024/7/11
 */
@Slf4j
public class HarborV2FeignConfig implements RequestInterceptor, ErrorDecoder, Decoder, ApplicationContextAware {

    private static final Decoder.Default DECODER_DEFAULT = new Decoder.Default();
    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
    private String getInstanceRepositoryAuthorization() {
        String property = context.getEnvironment().getProperty("pipeline.artifact.authorization.harbor");
        log.info("pipeline.artifact.authorization.harbor={}", property);
        return property;
    }

    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header(HttpHeaders.AUTHORIZATION, getInstanceRepositoryAuthorization());
    }

    @Override
    public Exception decode(String methodKey, Response response) {
        Exception exception = null;
        try {

            Response.Body body = response.body();
            String bodyString = Optional.ofNullable(body).map(Response.Body::toString).orElse("");
            ApiErrorXO apiErrorXO =  JSON.parseObject(bodyString, ApiErrorXO.class);
            ApiResponseXO<Void> result = new ApiResponseXO<>();
            if (apiErrorXO != null && !apiErrorXO.getErrors().isEmpty()) {
                result.setStatus(response.status());
                result.setId(apiErrorXO.getErrors().get(0).getCode());
                result.setMessage(apiErrorXO.getErrors().get(0).getMessage());
            } else {
                result.setStatus(response.status());
                result.setId("*");
                result.setMessage(response.reason());
            }
            exception = new ArtifactException(result);
            log.debug("Nexus3v1FeignConfig decode debug:{}", bodyString);
        } catch (Exception ex) {
            log.error("Nexus3v1FeignConfig decode error:{}", ex.getMessage());
            exception = ex;
        }
        return exception;
    }

    @Override
    public Object decode(Response response, Type type) throws IOException, FeignException {
        Type actualTypeArgument = ((ParameterizedType) type).getActualTypeArguments()[0];
        try {
            if (actualTypeArgument != null) {
                String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));
                return ApiResponseXO.builder().id("*").message("SUCCESS").status(response.status()).data(JSON.parseObject(bodyStr, actualTypeArgument)).build();
            }
        } catch (Exception exception) {
            log.error("Nexus3v1FeignConfig decode error:{}", exception.getMessage());
        }
        return DECODER_DEFAULT.decode(response, type);
    }

}
